package org.is.city;

import java.awt.Color;
import java.awt.Dimension;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
import org.geotools.map.MapContext;
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.swing.JMapPane;
import org.geotools.swing.MapLayerTable;
import org.geotools.swing.StatusBar;
import org.geotools.swing.action.InfoAction;
import org.geotools.swing.action.PanAction;
import org.geotools.swing.action.ResetAction;
import org.geotools.swing.action.ZoomInAction;
import org.geotools.swing.action.ZoomOutAction;
import org.is.city.layermanager.LayerPanel;
import org.is.city.pointsmanager.POImanager;
import org.is.city.routemanager.RoutePanel;
import org.is.city.search.SearchSettingsController;
import org.is.city.search.SearchToolbar;

/**
 *
 * @author oleg
 */
public class JMainFrame extends JFrame {
    /**
     * Constants for available toolbar buttons used with the
     * {@linkplain #enableTool} method.
     */
    public enum Tool {
        /**
         * Used to request that an empty toolbar be created
         */
        NONE,

        /**
         * Requests the feature info cursor tool
         */
        INFO,

        /**
         * Requests the pan cursor tool
         */
        PAN,

        /**
         * Requests the reset map extent cursor tool
         */
        RESET,

        /**
         * Requests the zoom in and out cursor tools
         */
        ZOOM;
    }

    private Set<Tool> toolSet;

    /*
     * UI elements
     */
    private JMapPane mapPane;
    private MapLayerTable mapLayerTable;
    private JToolBar toolBar;
    private StatusBar statusBar;

    private boolean showStatusBar;
    boolean showLayerTable;
    private boolean uiSet;


    /**
     * Default constructor. Creates a {@code JMapFrame} with
     * no context or renderer set
     */
    public JMainFrame() {
        this(null);
    }

    /**
     * Constructs a new {@code JMapFrame} object with specified context
     * and a default renderer (an instance of {@link StreamingRenderer}).
     *
     * @param context the map context with layers to be displayed
     */
    public JMainFrame(MapContext context) {
        this(context, new StreamingRenderer());
    }

    /**
     * Constructs a new {@code JMapFrame} object with specified context and renderer
     *
     * @param context the map context with layers to be displayed
     * @param renderer the renderer to be used
     */
    public JMainFrame(MapContext context, GTRenderer renderer) {
        super(context == null ? "" : context.getTitle());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        showLayerTable = false;
        showStatusBar = false;
        toolSet = new HashSet<Tool>();

        // the map pane is the one element that is always displayed
        mapPane = new JMapPane();
        mapPane.setBackground(Color.WHITE);
        mapPane.setMapContext(context);
        mapPane.setRenderer(renderer);
        this.setPreferredSize(new Dimension(800, 600));
    }


    /**
     * Creates and lays out the frame's components that have been
     * specified with the enable methods (e.g. {@linkplain #enableToolBar(boolean)} ).
     * If not called explicitly by the client this method will be invoked by
     * {@linkplain #setVisible(boolean) } when the frame is first shown.
     */
    public void initComponents() {
        if (uiSet) {
            // @todo log a warning ?
            return;
        }

        /*
         * We use the MigLayout manager to make it easy to manually code
         * our UI design
         */
        StringBuilder sb = new StringBuilder();
        if (!toolSet.isEmpty()) {
            sb.append("[]"); // fixed size
        }
        sb.append("[grow]"); // map pane and optionally layer table fill space
        if (showStatusBar) {
            sb.append("[30px::]"); // status bar height
        }

        JPanel panel = new JPanel(new MigLayout(
                "wrap 3, insets 0", // layout constrains: 1 component per row, no insets

                "[270!][grow][270!]", // column constraints: col grows when frame is resized

                sb.toString() ));
                    


        /*
         * A toolbar with buttons for zooming in, zooming out,
         * panning, and resetting the map to its full extent.
         * The cursor tool buttons (zooming and panning) are put
         * in a ButtonGroup.
         *
         * Note the use of the XXXAction objects which makes constructing
         * the tool bar buttons very simple.
         */
        if (!toolSet.isEmpty()) {
            toolBar = new JToolBar();
            toolBar.setOrientation(JToolBar.HORIZONTAL);
            toolBar.setFloatable(true);

            ButtonGroup cursorToolGrp = new ButtonGroup();

            JButton mycursotBtn = new JButton(new MouseNullCursor(mapPane));

            mycursotBtn.setIcon(new ImageIcon(JMainFrame.class.getResource("/default_mouse_cursor.png")));
            toolBar.add(mycursotBtn);
            cursorToolGrp.add(mycursotBtn);
            toolBar.addSeparator();

            if (toolSet.contains(Tool.ZOOM)) {
                JButton zoomInBtn = new JButton(new ZoomInAction(mapPane));
                toolBar.add(zoomInBtn);
                cursorToolGrp.add(zoomInBtn);

                JButton zoomOutBtn = new JButton(new ZoomOutAction(mapPane));
                toolBar.add(zoomOutBtn);
                cursorToolGrp.add(zoomOutBtn);

                toolBar.addSeparator();
            }

            if (toolSet.contains(Tool.PAN)) {
                JButton panBtn = new JButton(new PanAction(mapPane));
                toolBar.add(panBtn);
                cursorToolGrp.add(panBtn);

                toolBar.addSeparator();
            }

            if (toolSet.contains(Tool.INFO)) {
                JButton infoBtn = new JButton(new InfoAction(mapPane));
                toolBar.add(infoBtn);

                toolBar.addSeparator();
            }

            if (toolSet.contains(Tool.RESET)) {
                JButton resetBtn = new JButton(new ResetAction(mapPane));
                toolBar.add(resetBtn);
            }

            SearchToolbar st = new SearchToolbar(JToolBar.HORIZONTAL, new SearchSettingsController());
            JPanel temp=new JPanel();
            temp.add(st);
            temp.add(toolBar, "wrap");
            panel.add(temp,"wrap");
        }

        /*
         * добавляем слева панели "слои" и "маршруты"
         */
        if (showLayerTable) {
            POImanager pOImanager = new POImanager(mapPane,null);
            mapLayerTable = new RoutePanel(mapPane,pOImanager);
            pOImanager.setRoutePanel((RoutePanel) mapLayerTable);
            /*
             * We put the map layer panel and the map pane into a JSplitPane
             * so that the user can adjust their relative sizes as needed
             * during a session. The call to setPreferredSize for the layer
             * panel has the effect of setting the initial position of the
             * JSplitPane divider
             */

            //mapLayerTable.setPreferredSize(new Dimension(200, -1));
            
            JSplitPane vertSplit=new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, pOImanager, mapLayerTable);
            pOImanager.setPreferredSize(new Dimension(200, 200));
            pOImanager.setMinimumSize(new Dimension(200, 200));
            vertSplit.setDividerLocation(0.3);

            JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, false, vertSplit, mapPane);
            /*mapPane.setPreferredSize(new Dimension(300, -1));
            mapPane.setMinimumSize(new Dimension(400, -1));
            //panel.add(splitPane, "grow");
            LayerPanel layerPanel = new LayerPanel(mapPane);
            layerPanel.setPreferredSize(new Dimension(150, -1));
            layerPanel.setSize(new Dimension(150, -1));
            layerPanel.setMaximumSize(new Dimension(200, -1));
            JSplitPane biggerHorizontalSplit=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane, layerPanel);
            
            panel.add(biggerHorizontalSplit,"grow");
            //panel.add(new LayerPanel(mapPane), "grow");
             *
             */
            
            panel.add(vertSplit,"grow");
            panel.add(mapPane,"grow");
            panel.add(new LayerPanel(mapPane),"grow");

        } else {
            /*
             * No layer table, just the map pane
             */
            panel.add(mapPane, "grow");
        }

        if (showStatusBar) {
            statusBar = new StatusBar(mapPane);
            panel.add(statusBar, "grow");
        }
        
        this.getContentPane().add(panel);
        uiSet = true;
    }

    /**
     * Set whether a toolbar, with a basic set of map tools, will be displayed
     * (default is false). Calling this with state == true is equivalent to
     * calling {@linkplain #enableTool} with all {@linkplain JMapFrame.Tool}
     * constants.
     *
     * @param state whether the toolbar is required
     */
    public void enableToolBar(boolean state) {
        if (state) {
            toolSet.addAll(EnumSet.allOf(Tool.class));
        } else {
            toolSet.clear();
        }
    }

    /**
     * Creates a new {@code JMapFrame} object with a toolbar, map pane and status
     * bar; sets the supplied {@code MapContext}; and displays the frame on the
     * AWT event dispatching thread. The context's title is used as the frame's
     * title.
     *
     * @param context the map context containing the layers to display
     */
    public static void showMap(MapContext context) {
        final JMainFrame frame = new JMainFrame(context);
        //frame.enableStatusBar(true);
        //frame.enableToolBar(true);
        frame.initComponents();

        frame.setSize(500, 500);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                frame.setVisible(true);
            }
        });
    }
    
    /**
     * Set the MapContext object used by this frame.
     *
     * @param context a MapContext instance
     * @throws IllegalArgumentException if context is null
     */
    public void setMapContext(MapContext context) {
        if (context == null) {
            throw new IllegalArgumentException("context must not be null");
        }

        mapPane.setMapContext(context);
    }

    /**
     * Calls {@linkplain #initComponents()} if it has not already been called explicitly
     * to construct the frame's components before showing the frame.
     *
     * @param state true to show the frame; false to hide.
     */
    @Override
    public void setVisible(boolean state) {
        if (state && !uiSet) {
            initComponents();
        }

        super.setVisible(state);
    }

    /**
     * Set whether a map layer table will be displayed to show the list
     * of layers in the map context and set their order, visibility and
     * selected status.
     *
     * @param state whether the map layer table is required.
     */
    public void enableLayerTable(boolean state) {
        showLayerTable = state;
    }

    /**
     * Get the map context associated with this frame.
     * Returns {@code null} if no map context has been set explicitly with the
     * constructor or {@linkplain #setMapContext}.
     *
     * @return the current {@code MapContext} object
     */
    public MapContext getMapContext() {
        return mapPane.getMapContext();
    }

    /**
     * Provides access to the instance of {@code JMapPane} being used
     * by this frame.
     *
     * @return the {@code JMapPane} object
     */
    public JMapPane getMapPane() {
        return mapPane;
    }


    /**
     * Provides access to the toolbar being used by this frame.
     * If {@linkplain #initComponents} has not been called yet
     * this method will invoke it.
     *
     * @return the toolbar or null if the toolbar was not enabled
     */
    public JToolBar getToolBar() {
        if (!uiSet) initComponents();
        return toolBar;
    }
}
